package com.jin.webvideo.base.spring.resource;

import com.jin.webvideo.base.SpringBeanGetter;
import com.jin.webvideo.base.linkedfile.io.SeekableDataInputStream;
import com.jin.webvideo.base.linkedfile.io.SeekableInputStream;
import com.jin.webvideo.base.linkedfile.LinkedFile;
import com.jin.webvideo.base.linkedfile.util.InputStreamUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.core.io.Resource;

import java.io.*;
import java.net.*;

public class LinkedFileResource implements Resource {
    protected static final Logger logger = LoggerFactory.getLogger(LinkedFileResource.class);

    private static Cache cache = null;
    private static Cache getCache() {
        if (cache == null) {
            synchronized (LinkedFileResource.class) {
                if (cache == null) {
                    EhCacheCacheManager cacheManager = SpringBeanGetter.getBean(EhCacheCacheManager.class);
                    cache = cacheManager.getCache("vResource");
                }
            }
        }
        return cache;
    }

    private boolean isFile;
    private URI uri;
    private boolean exist = true;
    private LinkedFile linkedFile;

    public LinkedFileResource(boolean isFile, URI uri) {
        this.isFile = isFile;
        this.uri = uri;
        if (!isFile) {
            return;
        }

        Cache cache = getCache();
        this.linkedFile = cache.get(uri, LinkedFile.class);
        if (this.linkedFile != null) {
            logger.debug("find keyword {} from the cache", uri);
            return;
        }

        try {
            SeekableInputStream stream = getLinkedFileInputStream(uri);
            linkedFile = new LinkedFile(new SeekableDataInputStream(stream), uri);
            linkedFile.load();
            linkedFile.close();
            cache.put(uri, linkedFile);
            logger.debug("load and cache linkedFile from the {}", uri);
        } catch (IOException e) {
            logger.info("failed to load linkedFile from {}", uri);
            logger.info("ExceptionInfo", e);
            exist = false;
        }
    }
    @Override
    public boolean exists() {
        return exist;
    }

    @Override
    public boolean isFile() {
        return false;
    }

    @Override
    public File getFile() throws IOException {
        return null;
    }

    @Override
    public URL getURL() throws IOException {
        return getURI().toURL();
    }

    @Override
    public URI getURI() throws IOException {
        return this.uri;
    }

    @Override
    public long contentLength() throws IOException {
        if (isFile) {
            return linkedFile.getLength();
        }
        return 0;
    }

    @Override
    public long lastModified() throws IOException {
        return linkedFile.getLastModified();
    }

    @Override
    public Resource createRelative(String relativePath) throws IOException {
        return new LinkedFileResource(!relativePath.endsWith("/"), this.uri.resolve(relativePath));
    }

    @Override
    public String getFilename() {
        return linkedFile.getDescription();
    }

    @Override
    public String getDescription() {
        return "[file " + this.linkedFile + getDescription() + "]";
    }

    @Override
    public InputStream getInputStream() throws IOException {
        if (isFile && this.linkedFile != null) {
            return new LinkedFileResourceInputStream(this.linkedFile);
        }
        logger.debug("return nullInputStream isFile={}", isFile);
        return InputStream.nullInputStream();
    }

    private SeekableInputStream getLinkedFileInputStream(URI uri) throws IOException {
        InputStream inputStream = InputStreamUtils.getInputStreamByURI(uri, 3);
        // 最大缓存量12K
        return new SeekableInputStream(inputStream, 12*1024, true);
    }
}
